﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Media;
using IrrKlang;

namespace AlphaBeatSoundEngine
{
    public class AlphaBeatWillPlayLetterEventArgs : EventArgs
    {
        public int LetterIndex { get; set; }
        public AlphaBeatWillPlayLetterEventArgs() { }
        public AlphaBeatWillPlayLetterEventArgs(int letterIndex)
        {
            LetterIndex = letterIndex;
        }
    }

    public class AlphaBeatDidStopEventArgs : EventArgs { }

    public class AlphaBeat
    {
        public event EventHandler<AlphaBeatWillPlayLetterEventArgs> AlphaBeatWillPlayLetter;
        public event EventHandler<AlphaBeatDidStopEventArgs> AlphaBeatDidStop;

        //thread
        Thread _alphaBeatThread;
        private Boolean _threadHasToStop;

        //state
        private Boolean _isStarted;
        public Boolean IsStarted { get { return _isStarted; } }


        //sound engine
        private ISoundEngine _soundPlayer1;
        private ISound _currentPlayedSound;
        private Dictionary<String, ISoundSource> _soundSources;

        //word
        private MusicalWord _musicalWord;
        private int _nextLetterIndexToBePlayed = 0;
        private bool _isNewWord = false;
        public String CurrentWord { get { return _musicalWord.Word;}}

        public AlphaBeat()
        {
            
            _soundPlayer1 = new ISoundEngine();
            _soundSources = new Dictionary<string, ISoundSource>();

            Console.WriteLine("AlphaBeat starts loading");
            //loading every sounds
            ISoundSource source;
            foreach (MusicStyle style in MusicStyle.MusicStyles)
            {
                foreach (String sound in style.GetEveryAvailableSounds())
                {
                    if (!_soundSources.ContainsKey(sound))
                    {
                        source = _soundPlayer1.AddSoundSourceFromFile(sound);
                        _soundSources.Add(sound, source);
                    }
                }
                //marker sound
                String markerSound = style.TimeMarkerSoundLocation;
                int markerSoundVolume = style.TimeMarkerVolume;
                if (!_soundSources.ContainsKey(markerSound))
                {
                    source = _soundPlayer1.AddSoundSourceFromFile(markerSound);
                    source.DefaultVolume = markerSoundVolume / 100F;
                    _soundSources.Add(markerSound, source);
                }
            }

            Console.WriteLine("AlphaBeat finished loading");
        }

        public void Start()
        {
            if (!_isStarted && _musicalWord != null)
            {
                Console.WriteLine("AlphaBeat should start");

                _isStarted = true;
                _alphaBeatThread = new Thread(new ThreadStart(() =>
                {
                    int sleepingTime;
                    TimedTone nextTone;
                    ISoundSource source;

                    do
                    {
                        //stopping previous sound
                        if (_currentPlayedSound != null) _currentPlayedSound.Stop();
                        //getting tone to play
                        nextTone = this.NextTone();
                        //getting corresponding ISoundSource object
                        source = _soundSources[nextTone.SoundLocation];
                        //playing sound
                        Console.Write("Alphabeat should play : " + source.Name);
                        _currentPlayedSound = _soundPlayer1.Play2D(source, false, false, false);
                        //if there is a time marker, we get the source and play it
                        if (nextTone.TimeMarked)
                        {
                            _soundPlayer1.Play2D(_soundSources[nextTone.Style.TimeMarkerSoundLocation], false, false, false);
                        }
                        //setting sleeping time
                        sleepingTime = nextTone.ToneLenght.TimeInMillisecondForTempo(_musicalWord.Style.Tempo);
                        Console.WriteLine(" - will sleep for " + sleepingTime + "ms");
                        //sleep
                        Thread.Sleep(sleepingTime);

                    } while (!_threadHasToStop);

                    _threadHasToStop = false;
                    _isStarted = false;
                }));

                _alphaBeatThread.Name = "AlphaBeat";
                _alphaBeatThread.Start();
            }
        }

        public void Stop()
        {
            if (_isStarted)
            {
                Console.WriteLine("AlphaBeat should stop");
                _soundPlayer1.StopAllSounds();
                _threadHasToStop = true;

                if (this.AlphaBeatDidStop != null)
                    this.AlphaBeatDidStop(this, new AlphaBeatDidStopEventArgs());
            }
        }

        public void AddLetter()
        {
            throw new Exception("Not implemented yet");
        }

        public void EreaseLastLetter()
        {
            throw new Exception("Not implemented yet");
        }

        public void EreaseWord()
        {
            throw new Exception("Not implemented yet");
        }

        public void DefineWord(String word)
        {
            if (word.Length > 0 && word.Length <= 8)
            {
                ForceMusicalWord(new MusicalWord(word));
            }
        }

        public void ForceMusicalWord(MusicalWord word)
        {
            _musicalWord = word;
            _isNewWord = true;
            _nextLetterIndexToBePlayed = 0;
        }

        private TimedTone NextTone()
        {
            // Trigger de l'event
            if (this.AlphaBeatWillPlayLetter != null)
                AlphaBeatWillPlayLetter(this, new AlphaBeatWillPlayLetterEventArgs(_nextLetterIndexToBePlayed));

            TimedTone tone = _musicalWord.Pattern.Tones[_nextLetterIndexToBePlayed];

            _nextLetterIndexToBePlayed++;
            if (_nextLetterIndexToBePlayed >= _musicalWord.Word.Length)
            {
                _nextLetterIndexToBePlayed = 0;
            }

            _isNewWord = false;

            return tone;
        }
    }
}
